package game;


import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;


/**
 * Der Ball des Spiels.
 * Wird in der Klasse Arena verwendet und ist ein Objekt des Spielfelds.
 * Enthaelt eine Flaeche und Methoden, zum Bewegen des Balls.
 * 
 * @author mariuswi
 */
public class Pong implements  Drawable, Networkable{
    //Falls Bugfix Ausgaben zur Beschleunigung ewuenscht sind, auf TRUE setzen
    private final boolean BUGFIX = false;
    
    private Rectangle area;
    private float speedX, speedY;
    
    //Methoden-----------------------------------------------------
 
    Pong(){
        
    }
    
    /**
     * Initialisiert den Pong mit den gegebenen Attributen.
     * @param diameter Durchmesser des Balls
     * @param x xPosition der linken oberen Ecke
     * @param y yPosition der linken oberen Ecke
     * @param speedX Geschwindigkeit des Balls in xRichtung
     * @param speedY Geschwindigkeit des Balls in yRichtung
     */
    public void init(int diameter, int x, int y, float speedX, float speedY){
        this.area = new Rectangle(x,y,diameter,diameter); //Der Einfachheit halber ist der Pong ein Viereck
        this.speedX = speedX;
        this.speedY = speedY;     
    }
   
    @Override
    public void draw(GameContainer container, Graphics g) {
        g.setColor(Color.white);
        g.fillOval(this.area.getTopx()*GuiPlay.XFACTOR,this.area.getTopy()*GuiPlay.YFACTOR, this.area.getWidth()*GuiPlay.XFACTOR, this.area.getHeight()*GuiPlay.YFACTOR);
    }
    
    @Override
    public Rectangle getArea () {
        return area;
    }
    
    public float getSpeedX () {
        return speedX;
    }
    
    public float getSpeedY () {
        return speedY;
    }
    
    /**
     * Verpasst dem Ball ein neues Rechteck als Flaeche
     * @param newArea 
     */
    public void setArea(Rectangle newArea) {
        this.area = newArea;
    }
    
    public void setSpeedX (float newSpeedX) {
        this.speedX = newSpeedX;
    }
    
    public void setSpeedY (float newSpeedY) {
        this.speedY = newSpeedY;
    }
    
    /**
     * Bewegt Pong um einen Schritt, definiert durch speedX und speedY
     * @param shouldRoundUp false Bewegt den Pong einen Schritt um gespeicherte speedX und speedY Werte
     *                      true  Rundet Bewegungswerte unter 1 bzw. -1 auf 1 bzw -1 auf und verhindert so das Steckenbleiben des Balles
     */
    public void moveAStep (boolean shouldRoundUp) {
        if (this.BUGFIX) {
            System.out.println("pong.moveAStep meldet: Beschleunigungen (\t"+speedX+"\t|\t"+speedY+"\t)");
        }
        
        //Gerundete Geschwindigkeitswerte initialisieren
        int speedXRounded, speedYRounded;
        
        //SpeedX wird abgearbeitet
        if (shouldRoundUp) { //Falls gewuenscht. Betraege kleiner null aufrunden
            if (this.speedX < 1 && this.speedX > 0) { //Geschwindigkeiten mit einem Betrag kleiner eins werden aufgerundet
                speedXRounded = 1;
            }
            else if (this.speedX > -1 && this.speedX < 0) {
                speedXRounded = -1;
            }
            else {
                speedXRounded = Math.round(this.speedX);
            }
        }
        else {
            speedXRounded = Math.round(this.speedX);
        }
        
        //SpeedY wird abgearbeitet
        if (shouldRoundUp) { //Falls gewuenscht. Betraege kleiner null aufrunden
            if (this.speedY < 1 && this.speedY > 0) { //Geschwindigkeiten mit einem Betrag kleiner eins werden aufgerundet
                speedYRounded = 1;
            }
            else if (this.speedY > -1 && this.speedY < 0) {
                speedYRounded = -1;
            }
            else {
                speedYRounded = Math.round(this.speedY);
            }
        }
        else {
            speedYRounded = Math.round(this.speedY);
        }
        
        //Success: speedX und speedY wurden beide richtig gerundet
        
        // Pong um einen Schritt bewegen
        this.area.setPosition(this.area.getTopx()+speedXRounded, this.area.getTopy()+speedYRounded);
        if (this.BUGFIX) {
            System.out.println("pong.moveAStep meldet: Beschleunigungen (\t"+speedXRounded+"\t|\t"+speedYRounded+"\t)");
        }
    }
    
    /**
     * Beschleunigt den Pong. Multipliziert x und y Geschwindigkeit mit dem Wert Accelleration
     * @param accelleration 
     */
    public void accellerate(float accelleration) {
        this.speedX = this.speedX * accelleration;
        this.speedY = this.speedY * accelleration;
    }
    
    /**
     * Dreht den Bewegungswinkel im Uhrzeigersinn
     * @param angle Angabe des Winkels im Rad-Format (2*Pi = 360°)
     */
    public void changeMovingAngle (float angle) {
        this.speedX = (float) (((double) this.speedX) * Math.cos( angle) - ((double) this.speedY) * Math.sin( angle) );
        this.speedY = (float) (((double) this.speedY) * Math.cos( angle) + ((double) this.speedX) * Math.sin( angle) );
    }
    
    /**
     * Berechnet die Gesamtgeschwindigkeit durch folgende Formel: Wurzel aus Vx²+Vy²
     * @return Gesamtgeschwindigkeit des Pongs
     */
    public float getTotalSpeed () {
        float totalSpeed = (float) Math.sqrt( Math.pow(this.speedX, 2.0) + Math.pow(this.speedY, 2.0));
        return totalSpeed;
    }
}
